﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media.Media3D;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.IO;

namespace Eniux.Windows.ThreeDEngine.Helper
{
    /// <summary>
    /// 材质帮助类
    /// </summary>
    public static class MaterialHelper
    {
        #region 常量、字段

        /// <summary>
        ///   默认镜面强度
        /// </summary>
        public static double DefaultSpecularPower = 100;

        #endregion

        #region 方法

        /// <summary>
        /// 改变材质的透明度
        /// </summary>
        /// <param name="material">材质</param>
        /// <param name="d">透明度</param>
        public static void ChangeOpacity(Material material, double d)
        {
            var mg = material as MaterialGroup;
            if (mg != null)
            {
                foreach (var m in mg.Children)
                {
                    ChangeOpacity(m, d);
                }
            }

            var dm = material as DiffuseMaterial;
            if (dm != null)
            {
                var scb = dm.Brush as SolidColorBrush;
                if (scb != null)
                {
                    scb.Opacity = d;
                }
            }
        }

        /// <summary>
        /// 创建图片材质
        /// </summary>
        /// <param name="path">图片路径</param>
        /// <returns>图片材质</returns>
        public static Material CreateImageMaterial(string path)
        {
            return CreateImageMaterial(path, 1);
        }

        /// <summary>
        /// 创建图片材质
        /// </summary>
        /// <param name="path">图片路径</param>
        /// <param name="opacity">图片透明度</param>
        /// <returns>图片材质</returns>
        public static Material CreateImageMaterial(string path, double opacity)
        {
            var fullPath = Path.GetFullPath(path);
            if (!File.Exists(fullPath))
            {
                return null;
            }

            var image = new BitmapImage();
            image.BeginInit();
            image.UriSource = new Uri(fullPath);
            image.EndInit();
            return CreateImageMaterial(image, opacity);
        }

        /// <summary>
        /// 创建图片材质
        /// </summary>
        /// <param name="image">图片</param>
        /// <param name="opacity">图片透明度</param>
        /// <returns>图片材质</returns>
        public static Material CreateImageMaterial(BitmapImage image, double opacity)
        {
            var brush = new ImageBrush(image);
            brush.Opacity = opacity;
            return new DiffuseMaterial(brush);
        }

        /// <summary>
        /// 创建纯色材质
        /// </summary>
        /// <param name="color">颜色</param>
        /// <returns>纯色材质</returns>
        public static Material CreateMaterial(Color color)
        {
            return CreateMaterial(new SolidColorBrush(color));
        }

        /// <summary>
        /// 创建纯色材质
        /// </summary>
        /// <param name="color">颜色</param>
        /// <param name="opacity">颜色透明度</param>
        /// <returns>纯色材质</returns>
        public static Material CreateMaterial(Color color, double opacity)
        {
            return CreateMaterial(Color.FromArgb((byte)(opacity * 255), color.R, color.G, color.B));
        }

        /// <summary>
        /// 创建笔刷材质
        /// </summary>
        /// <param name="brush">笔刷</param>
        /// <returns>笔刷材质</returns>
        public static Material CreateMaterial(Brush brush)
        {
            return CreateMaterial(brush, DefaultSpecularPower);
        }

        /// <summary>
        /// 创建笔刷材质
        /// </summary>
        /// <param name="brush">笔刷</param>
        /// <param name="specularPower">镜面强度</param>
        /// <returns>笔刷材质</returns>
        public static Material CreateMaterial(Brush brush, double specularPower)
        {
            var mg = new MaterialGroup();
            mg.Children.Add(new DiffuseMaterial(brush));
            if (specularPower > 0)
            {
                mg.Children.Add(new SpecularMaterial(Brushes.White, specularPower));
            }

            return mg;
        }

        /// <summary>
        /// 创建具有指定漫射、发射、镜面、透明度、镜面强度的的材质
        /// </summary>
        /// <param name="diffuse">漫射笔刷</param>
        /// <param name="emissive">发射笔刷</param>
        /// <param name="specular">镜面笔刷</param>
        /// <param name="opacity">透明度</param>
        /// <param name="specularPower">镜面强度</param>
        /// <returns>材质</returns>
        public static Material CreateMaterial(
            Brush diffuse, Brush emissive = null, Brush specular = null, double opacity = 1, double specularPower = 85)
        {
            var mg = new MaterialGroup();
            if (diffuse != null)
            {
                diffuse = diffuse.Clone();
                diffuse.Opacity = opacity;
                mg.Children.Add(new DiffuseMaterial(diffuse));
            }

            if (emissive != null)
            {
                emissive = emissive.Clone();
                emissive.Opacity = opacity;
                mg.Children.Add(new EmissiveMaterial(emissive));
            }

            if (specular != null)
            {
                specular = specular.Clone();
                specular.Opacity = opacity;
                mg.Children.Add(new SpecularMaterial(specular, specularPower));
            }

            return mg;
        }

        #endregion

        #region 辅助
        /// <summary>
        /// 获取指定类型的材质
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="material">材质</param>
        /// <returns>材质</returns>
        public static T GetFirst<T>(Material material) where T : Material
        {
            if (material.GetType() == typeof(T))
                return (T)material;

            var mg = material as MaterialGroup;
            if (mg != null)
                foreach (var m in mg.Children)
                {
                    var result = GetFirst<T>(m);
                    if (result != null) return result;
                }
            return null;
        } 
        #endregion
    }
}
